package org.geektimes.configuration.microprofile.source;

import org.eclipse.microprofile.config.spi.ConfigSource;

import java.util.*;
import java.util.stream.Stream;

/**
 * @Author: jipeng
 * @Description:
 * @Date: Created in 2021/3/19 8:44
 */
public class ConfigSources implements Iterable<ConfigSource> {


    private boolean addedDefaultConfigSource;

    private boolean addedDiscoveredConfigSource;

    private List<ConfigSource> configSources = new LinkedList<>();

    private ClassLoader classLoader;

    public ConfigSources(ClassLoader classLoader){
        this.classLoader = classLoader;
    }

    /**
     * 添加默认的数据源
     */
    public void addDefaultSources(){
        if(addedDefaultConfigSource){
            return;
        }

        addConfigSources(JavaSystemEnvironmentConfigSource.class,
                JavaSystemPropertiesConfigSource.class,
                DefaultResourceConfigSource.class);
        addedDefaultConfigSource = true;
    }

    /**
     * 添加发现的数据源
     */
    public void addDiscoveredConfigSources(){
        if(addedDiscoveredConfigSource){
            return;
        }

        addConfigSources(ServiceLoader.load(ConfigSource.class,classLoader));
        addedDiscoveredConfigSource = true;
    }

    /**
     * 添加数据源
     * 参数为实现 {@link ConfigSource} 的类数组
     * @param configSourceClasses
     */
    public void addConfigSources(Class<? extends ConfigSource>... configSourceClasses){
        addConfigSource(
                Stream.of(configSourceClasses)
                        .map(this::newInstance)
                        .toArray(ConfigSource[]::new));
    }


    /**
     * 添加数据源
     * 参数为 {@link ConfigSource} 接口
     * @param configSources
     */
    public void addConfigSource(ConfigSource... configSources){
        addConfigSources(Arrays.asList(configSources));
    }

    /**
     * 添加数据源
     * @param configSources
     */
    public void addConfigSources(Iterable<ConfigSource> configSources){
        configSources.forEach(this.configSources::add);
        Collections.sort(this.configSources,ConfigSourceOrdinalComparator.INSTANCE);
    }


    /**
     * 根据类型实例化一个实现{@link ConfigSource} 的类
     * @param configSourceClass
     * @return
     */
    private ConfigSource newInstance(Class<? extends ConfigSource> configSourceClass) {
        ConfigSource instance = null;
        try {
            instance = configSourceClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
        return instance;
    }



    @Override
    public Iterator<ConfigSource> iterator() {
        return configSources.iterator();
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }

    public void setClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public boolean isAddedDefaultConfigSource(){
        return addedDefaultConfigSource;
    }

    public boolean isAddedDiscoveredConfigSource(){
        return addedDiscoveredConfigSource;
    }
}
